#include "fs.h"
#include "str.h"
#include "idir.h"
#include "errno.h"

namespace log4x
{
bool
fs::exists(const string& path)
{
    string pathname = path;
    path_to_unix(pathname);

    if (os::dir()->access(pathname, 0x0) < 0)
    {
        return false;
    }
    return true;
}

bool
fs::is_dir(const string& path)
{
    return os::dir()->is_dir(path);
}

int
fs::mk_dir(const string& path)
{
    return os::dir()->mk_dir(path);
}

int
fs::ls_dir(const string& path, vector<string>& files)
{
    string pathname = path;
    path_to_unix(pathname);

    if (pathname[pathname.size() - 1] != '/')
    {
        pathname += "/";
    }
    return os::dir()->ls_dir(pathname, files);
}

size_t
fs::file_size(const string& path)
{
    string pathname = path;
    path_to_unix(pathname);

    if (!exists(pathname))
    {
        return -1;
    }

    struct stat sb;
    if (os::dir()->stat(pathname.c_str(), sb) < 0)
    {
        return -1;
    }

    return (size_t)sb.st_size;
}

int
fs::chmod(const string& path, uint32_t mode)
{
    string pathname = path;
    path_to_unix(pathname);

    if (!exists(pathname))
    {
        return -1;
    }
    return os::dir()->chmod(path, mode);
}

int fs::copy(const string& from, const string& to)
{
    string prefix = shortname(to);
    if (!prefix.empty() && !exists(prefix))
    {
        mk_dir(prefix);
    }

    if (is_dir(from))
    {
        os::dir()->copy_dir(from, to);
        return 0;
    }

    string dst = to;
    if (is_dir(to))
    {
        dst = to + "/" + basename(from);
    }

    return os::dir()->copy(from, dst);
}

bool
fs::remove(const string& path)
{
    if (!exists(path))
    {
        return false;
    }

    os::dir()->remove(path);
    return true;
}

int
fs::rename(const string& from, const string& to)
{
    if (!exists(from))
    {
        return -1;
    }

    if (::rename(from.c_str(), to.c_str()) < 0)
    {
        return -1;
    }
    return 0;
}

string&
fs::path_to_win(string& unix_path)
{
    for (string::iterator iter = unix_path.begin(); iter != unix_path.end(); ++iter)
    {
        if (*iter == '/')
        {
            *iter = '\\';
        }
    }
    return unix_path;
}

string&
fs::path_to_unix(string& win_path)
{
    for (string::iterator iter = win_path.begin(); iter != win_path.end(); ++iter)
    {
        if (*iter == '\\')
        {
            *iter = '/';
        }
    }
    return win_path;
}

string
fs::basename(const string& fpath)
{
    string unix_path = fpath;
    path_to_unix(unix_path);

    vector<string> parts;
    str::split(unix_path, "/", parts);
    if (parts.empty())
    {
        return "";
    }

    return parts.back();
}

string
fs::shortname(const string& fpath)
{
    string::size_type pos = fpath.rfind('/');
    if (string::npos == pos)
    {
        pos = fpath.rfind('\\');
        if (string::npos == pos)
        {
            return "";
        }
    }

    return fpath.substr(0, pos);
}

string
fs::stem(const string& fpath)
{
    string filename = basename(fpath);
    vector<string> parts;
    str::split(filename, ".", parts);
    return parts.front();
}

string
fs::extension(const string& fpath)
{
    string filename = basename(fpath);
    vector<string> parts;
    str::split(filename, ".", parts);
    if (parts.size() >= 2)
    {
        return "." + parts[parts.size() - 1];
    }
    return "";
}

string
fs::absolute_path(const string& relative_path)
{
    string path = os::dir()->absolute_path(relative_path);
    fs::path_to_unix(path);

    if (path[path.size() - 1] == '/')
    {
        /* 统一遵循Linux realpath处理方式, 将后面的斜杠去掉 */
        path.erase(path.end() - 1);
    }
    return path;
}

}
